#!/usr/bin/env python
# vim: set fileencoding=utf-8 :
'''Simple python server to display an index page and static objects.
    .. note:: External module included: webpy (http://webpy.org/)
    .. moduleauthor:: balzano

Usage:
    >>> # call the class from top level
    >>> start_server.py
'''

from __future__ import with_statement, absolute_import, print_function
from optparse import OptionParser
import sys
import os
import logging
import time
from itertools import chain
# webpy
from . import web
# config file
from . import config_pyanalyze
# rendering file
from .lib_render import *

from .lib_database import PyAnalyzeDatabase
# database
from . import lib_database

#from .lib_user import User
    
# port range to run the server
MIN_PORT = 1024
MAX_PORT = 65535
# refresh time in seconds to reload the main page
REFRESH_TIME = 90
# first line in the html to be displayed in the browser
START_RENDERING = 1
# Default clientID
CLIENTID_DF = '000000000'


class Index:
    ''' Class that serves the main page.
    Will search for a .html file under the folder set in render below.
    '''
    db_object = []
    def __init__(self):
        # search for the main page that will be displayed in the templates dir
        self.render = web.template.render(config_pyanalyze.TEMPLATES_DIR,
                                          cache=False)

    def GET(self, parameter):
        '''Retrieves the main page from the parameter_timestamp_index.html
        template, based on the selected clientID as parameter.
        '''
        # verify if the user has already specified a certain clientID on which
        # to display the plots, otherwise choose the latest clientID
        # clientID is a parameter in the link
        # example: http://127.0.0.1:5555/General_Metrics?db=284676141
        # has as 'db' parameter the database with the clientID '284676141'
        try:
            
            # ----- Modified for students VM ------
            #clientID = web.input().db
            user = PyAnalyzeDatabase('000000000')
            
            clientID = str(user.get_clientID())
            # print(clientID)
            # --------------------------------
            
            print('clientID selected = '+clientID)
            config_pyanalyze.CLIENTID = clientID
            config_pyanalyze.TEMPLATES_DIR = 'templates/'+str(clientID)            
        except AttributeError:
            global CLIENTID_DF
            print('Default clientID selected '+CLIENTID_DF)
            clientID = CLIENTID_DF    
        
        
        
        # First check if, in the global database, there are saved sessions       
        # with the selected clientID
        if clientID != '000000000' and clientID != None:          
            try:
                user = PyAnalyzeDatabase(clientID)
                # clientID = str(user.get_clientID())
                # INSERT IF NOT EXISTS
                user.insert_user()        
                #config_pyanalyze.LOG.critical('User connected %s', str(clientID))
                # Counting rows 
                db_nr_rows = int(user.count_rows())
                if not db_nr_rows:
                    nr_ext_rows = user.fetch_ext_rows()
                    print('Counted rows',db_nr_rows,'| Saved rows', nr_ext_rows)
                    if nr_ext_rows == None:
                        user.set_ext_rows(db_nr_rows)
                
            except:
                print('Unable to extract data with error')
            
            # db_nr_rows = None
            if not db_nr_rows:
                print('Database %s does not have enough points'
                                          ' to create statistics' % clientID)
                timestamp = None
                write_index(timestamp, clientID)
            else:
                try:
                    timestamp = user.fetch_min_time()
                    # timestamp = None
                    print('Valid Timestamp-->',timestamp)
                except:
                    timestamp = None
                    print('Unable to extract timestamp:')
                
                # check if:
                # template files don't exist
                # or if there is a new row into the database that is not in the list
                            
                #OR that I eliminated
                #((time.time() - os.path.getmtime(index_filename(GEN_KEY, timestamp))) < REFRESH_TIME)  or 
                if (not check_templates_exist(timestamp)
                        or user.fetch_ext_rows() != db_nr_rows):
                    user.set_ext_rows(db_nr_rows)
                    user.drop_sid_table()
                    clientID = str(user.get_clientID())
                    write_index(timestamp, clientID)
                    
                    
            print('Start rendering page...')
            # these headers allow browsers to display the page
            web.header('Content-type','text/html')
            web.header('Transfer-Encoding','chunked')
            
            # if the user provides a legitimate link, it will be displayed
            # otherwise the General Metrics will be displayed
            # parameter is taken from the link, for example:
            # http://127.0.0.1:5555/Browsed_Websites
            # has as parameter 'Browsed_Websites'
            if (parameter in chain(ALL_PAGES)):
                template_file = index_filename(parameter, timestamp)
                str_log = ' '.join(('User connected %s on page ' % str(clientID), parameter))
                config_pyanalyze.LOG.critical(str_log)
                
            else:
                print('NO PARAMETER')
                template_file = index_filename(GEN_KEY, timestamp)
                config_pyanalyze.LOG.critical('User connected %s on page  General_Metrics', str(clientID))
                
            try:
                f_index = open(template_file, 'r')
            except IOError:
                print('Template file %s does not exist!' %
                                        template_file)
            # skip the first line that allows to process the parameter given by the
            # link
            for line in f_index.readlines()[START_RENDERING:]:
                yield line
            f_index.close()
        
            print('End rendering page...')
        
        
            


class Static:
    ''' Class that serves the static objects of the main page.
    Will search for elements under the directories mentioned in urls related to
    this class.
    '''
    def __init__(self):
        self.object_path = None

    def GET(self, media, filename):
        '''Retrieves the static objects located in the main page.'''
        try:
            self.object_path = open(media + '/' + filename, 'rb')
        except IOError, mes:
            print('File, %s, does not exist.' % filename)
        yield self.object_path.read()


class Pdf:
    ''' Class that serves the PDF reports.
    Will search for elements under the directories mentioned in urls related to
    this class.
    '''
    def __init__(self):
        self.object_path = None

    def GET(self, media, filename):
        '''Retrieves the static objects located in the main page.'''
        # these headers allow browsers to display the page
        # if commented, the browser will open the page. if not, a pop-up to save it will come up
        # POP-UP DOES NOT WORK WITH CHROME FOR LINUX (JUST CHROMIUM)
        web.header('Content-type','application/octet-stream')
        
        try:
            self.object_path = open(media + '/' + filename, 'rb')
        except IOError, mes:
            print('File, %s, does not exist.' % filename)
        yield self.object_path.read()
        
        
def configure_logger_web():
    'Configure log file and indicate succes or failure'
    print('Configuring log file')
    config_pyanalyze.LOG = logging.getLogger('pyanalyze_webpage')
    timestamp = time.strftime("%Y-%m-%d.%H_%M_%S")
    if config_pyanalyze.LOG_FILE == '-':
        handler = logging.StreamHandler(sys.stdout)
        print('Logs are on standard output')
        log_file = True
    else:
        try:
            log_file = check_out_files(config_pyanalyze.LOG_FILE,
                                       config_pyanalyze.LOG_DIR, timestamp)
        except IOError:
            print('Problem opening file with timestamp: %s' % timestamp)
            return None
        #print('Graphical web interface logs are there: %s' % log_file)
        # for lib_youtube_download
        handler = logging.FileHandler(filename=log_file)
    log_formatter = logging.Formatter('%(asctime)s - %(filename)s:%(lineno)d - '
                                      '%(levelname)s - %(message)s')
    handler.setFormatter(log_formatter)
    config_pyanalyze.LOG.addHandler(handler)
    config_pyanalyze.LOG.setLevel(config_pyanalyze.LOG_LEVEL)
    config_pyanalyze.LOG.critical('Log level set to %s',
                           config_pyanalyze.LEVEL_TO_NAME[config_pyanalyze.LOG_LEVEL])
    # to not have console output
    config_pyanalyze.LOG.propagate = False
    # log all config file values except built in values

#     ALL LOGS
#     for value in filter(lambda x: not x.startswith('__'),
#                         config_pyanalyze.__dict__):
#         config_pyanalyze.LOG.critical('%s: %s'
#                                    % (value, getattr(config_pyanalyze, value)))
#      


def main(argv=None):
    'Program wrapper'
    
    args = sys.argv[1:]
    
    if not config_pyanalyze.LOG:
        configure_logger_web()
                
    # set port for web server
    port = None
    if len(args) == 0:
        # add default port
        port = int(config_pyanalyze.WEB_DEFAULT_PORT)
    elif len(args) == 1:
        # set port
        try:
            port = int(args[0])
        except ValueError, mes:
            print('You must specify an integer in the range [%d,%d]'
                % (MIN_PORT, MAX_PORT))
        if (port < MIN_PORT or port > MAX_PORT):
            print('Port %d is not in the range [%d,%d])' %
                         (port, MIN_PORT, MAX_PORT))
    else:
        print('Only the port on which to run the application should be '
                'specified, in the range [%d,%d]' % (MIN_PORT, MAX_PORT))
    
    
    if not CLIENTID_DF:
        print('ERROR\n')
        return 1
    print('Initial clientID: %s' % CLIENTID_DF)
    # the main page (index)
    # static objects found under folders below in the current dir
    # each element is treated by its respective class
    urls = (
        '/(js|css|%s|%s)/(.*)' % (config_pyanalyze.IMAGE_DIR,
                                  config_pyanalyze.RRD_PLOT_DIR), 'Static',
        '/(%s)/(.*)' % (config_pyanalyze.PDF_DIR), 'Pdf',
        '/%s(.*)' % config_pyanalyze.DOC_DIR, 'Doc',
        '/(.*)', 'Index'
        )
    # hack due to the  fact that web.application.__init__() expects the
    # globals() dictionary as second parameter, so application would only
    # work with port number as option (no -v or anything else)
    app = web.application(urls, {'Static': Static,  'Pdf': Pdf, 'Index': Index}, autoreload=True)
    
    # hack due to line 54 in /usr/lib/pymodules/python2.6/web/wsgi.py
    # return httpserver.runsimple(func, validip(listget(sys.argv, 1, '')))
    if len(sys.argv) == 0 or len(sys.argv) == 1:
        sys.argv.append(str(port))
    else:
        sys.argv[1] = str(port)
    try:
        print('Launching server on port %d' % port)
        print('Type Ctrl-C to stop server.')
        app.run()
    except IOError:
        print('Address already in use, start the application with '
                'another port number in the range [%d,%d])'
                % (MIN_PORT,MAX_PORT))
    except KeyboardInterrupt:
        print('\nServer stopped by user')
        config_pyanalyze.LOG.critical('Server stopped by user')
        return 1
    return 0

if __name__ == '__main__':
    import doctest
    doctest.testmod()
    sys.exit(main())
